package br.edu.ufcg.lsd.wbis.control.user;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

import java.util.List;

import org.junit.Test;

import br.edu.ufcg.lsd.wbis.DatabaseTestCase;
import br.edu.ufcg.lsd.wbis.control.exception.CannotOpenDatabaseSessionException;

@SuppressWarnings("unchecked")
public class HibernateUserDAOTest extends DatabaseTestCase {

	UserDAO hibernateUserDAO;
	
	@Override
	public void setUp() throws Exception {
		super.setUp();
		hibernateUserDAO = new HibernateUserDAO();
	}
	
	@Override
	public void tearDown() throws Exception {
		super.tearDown();
		hibernateUserDAO = null;
	}
	
	@Test
	public void testAddUser() throws CannotOpenDatabaseSessionException {
		// Check if the database is empty
		session.beginTransaction();
		List<User> allusers = session.createQuery("from " + User.class.getCanonicalName()).list();
		assertTrue(allusers.isEmpty());
		session.getTransaction().commit();

		// Add user John
		User john = new User("John", "john@gmail.com", "john", "johnpass", false, UserLevel.COMMON_USER);
		hibernateUserDAO.addUser(john);

		// Check if user John is on the DB
		session.beginTransaction();
		User returnedUser = (User) session.createQuery("from " + User.class.getCanonicalName() + " where login=\'john\'").uniqueResult();
		assertEquals(john, returnedUser);
		session.getTransaction().commit();

		// Add user Jack
		User jack = new User("Jack", "jack@admin.net", "jack", "4dm1n", true, UserLevel.ADMIN);
		hibernateUserDAO.addUser(jack);

		// Check if user Jack is on the DB
		session.beginTransaction();
		returnedUser = (User) session.createQuery("from " + User.class.getCanonicalName() + " where login=\'jack\'").uniqueResult();
		assertEquals(jack, returnedUser);

		// Check if both users are on the DB
		allusers = session.createQuery("from " + User.class.getCanonicalName()).list();
		assertEquals(2, allusers.size());
		assertTrue(allusers.contains(john));
		assertTrue(allusers.contains(jack));
		session.getTransaction().commit();
	}

	@Test
	public void testGetUsers() throws CannotOpenDatabaseSessionException {
		// Check if there are no users in the db
		List<User> allUsers = hibernateUserDAO.getUsers();
		assertTrue(allUsers.isEmpty());

		// Populate users
		session.beginTransaction();
		User john = new User("John", "john@gmail.com", "john", "johnpass", false, UserLevel.COMMON_USER);
		User jack = new User("Jack", "jack@admin.net", "jack", "4dm1n", true, UserLevel.ADMIN);
		session.save(john);
		session.save(jack);
		session.getTransaction().commit();

		// Check if user dao returns just the users previously populated
		allUsers = hibernateUserDAO.getUsers();
		assertEquals(2, allUsers.size());
		assertTrue(allUsers.contains(john));
		assertTrue(allUsers.contains(jack));
	}

	@Test
	public void testRemoveUsers() throws CannotOpenDatabaseSessionException {

		session.beginTransaction();
		// Populate users
		User john = new User("John", "john@gmail.com", "john", "johnpass", false, UserLevel.COMMON_USER);
		User jack = new User("Jack", "jack@admin.net", "jack", "4dm1n", true, UserLevel.ADMIN);
		User mary = new User("Mary", "mary@gmail.com", "mary", "12345", false, UserLevel.COMMON_USER);
		User ornophre = new User("Ornophre Pinto", "orninho@bol.com.br", "ornophre", "abc", true, UserLevel.COMMON_USER);
		session.save(john);
		session.save(jack);
		session.save(mary);
		session.save(ornophre);

		// Check if all users are on the DB
		List<User> allusers = session.createQuery("from " + User.class.getCanonicalName()).list();
		assertEquals(4, allusers.size());
		assertTrue(allusers.contains(john));
		assertTrue(allusers.contains(jack));
		assertTrue(allusers.contains(mary));
		assertTrue(allusers.contains(ornophre));
		session.getTransaction().commit();

		hibernateUserDAO.removeUser(mary);

		session.beginTransaction();
		// Check if all users except mary are on the DB
		allusers = session.createQuery("from " + User.class.getCanonicalName()).list();
		assertEquals(3, allusers.size());
		assertTrue(allusers.contains(john));
		assertTrue(allusers.contains(jack));
		assertTrue(allusers.contains(ornophre));
		session.getTransaction().commit();

		hibernateUserDAO.removeUser(john);

		session.beginTransaction();
		// Check if all users except mary and john are on the DB
		allusers = session.createQuery("from " + User.class.getCanonicalName()).list();
		assertEquals(2, allusers.size());
		assertTrue(allusers.contains(jack));
		assertTrue(allusers.contains(ornophre));
		session.getTransaction().commit();
	}

	@Test
	public void testUpdateUser() throws CannotOpenDatabaseSessionException {

		// Check if the database is empty
		session.beginTransaction();
		List<User> allusers = session.createQuery("from " + User.class.getCanonicalName()).list();
		assertTrue(allusers.isEmpty());
		session.getTransaction().commit();

		// Add user John
		session.beginTransaction();
		User john = new User("John", "john@gmail.com", "john", "johnpass", false, UserLevel.COMMON_USER);
		session.save(john);

		// Check if user John is on the DB
		User returnedUser = (User) session.createQuery("from " + User.class.getCanonicalName() + " where login=\'john\'").uniqueResult();
		assertEquals(john, returnedUser);
		session.getTransaction().commit();

		// Update user John
		john.setName("John Deer");
		john.setEmail("john@oracle.com");
		hibernateUserDAO.updateUser(john);

		// Check if user John was updated
		session.beginTransaction();
		returnedUser = (User) session.createQuery("from " + User.class.getCanonicalName() + " where login=\'john\'").uniqueResult();
		assertEquals(john, returnedUser);
		session.getTransaction().commit();

		session.beginTransaction();
		// Add user Jack
		User jack = new User("Jack", "jack@admin.net", "jack", "4dm1n", true, UserLevel.ADMIN);
		hibernateUserDAO.addUser(jack);

		// Check if user Jack is on the DB
		returnedUser = (User) session.createQuery("from " + User.class.getCanonicalName() + " where login=\'jack\'").uniqueResult();
		assertEquals(jack, returnedUser);
		session.getTransaction().commit();

		// Update user John
		john.setLevel(UserLevel.COMMON_USER);
		hibernateUserDAO.updateUser(jack);

		// Check if user Jack was updated
		session.beginTransaction();
		returnedUser = (User) session.createQuery("from " + User.class.getCanonicalName() + " where login=\'jack\'").uniqueResult();
		assertEquals(jack, returnedUser);
		session.getTransaction().commit();
	}

	@Test
	public void testAll() throws CannotOpenDatabaseSessionException {

		// Populate users
		User john = new User("John", "john@gmail.com", "john", "johnpass", false, UserLevel.COMMON_USER);
		User jack = new User("Jack", "jack@admin.net", "jack", "4dm1n", true, UserLevel.ADMIN);
		User mary = new User("Mary", "mary@gmail.com", "mary", "12345", false, UserLevel.COMMON_USER);
		User ornophre = new User("Ornophre Pinto", "orninho@bol.com.br", "ornophre", "abc", false, UserLevel.COMMON_USER);
		hibernateUserDAO.addUser(john);
		hibernateUserDAO.addUser(jack);
		hibernateUserDAO.addUser(mary);
		hibernateUserDAO.addUser(ornophre);

		// Check if all users are on the DB
		List<User> allusers = hibernateUserDAO.getUsers();
		assertEquals(4, allusers.size());
		assertTrue(allusers.contains(john));
		assertTrue(allusers.contains(jack));
		assertTrue(allusers.contains(mary));
		assertTrue(allusers.contains(ornophre));

		hibernateUserDAO.removeUser(mary);

		// Check if all users except mary are on the DB
		allusers = hibernateUserDAO.getUsers();
		assertEquals(3, allusers.size());
		assertTrue(allusers.contains(john));
		assertTrue(allusers.contains(jack));
		assertTrue(allusers.contains(ornophre));

		hibernateUserDAO.removeUser(john);

		ornophre.setName("Ornophrino Silva");
		hibernateUserDAO.updateUser(ornophre);

		// Check if all users except mary and john are on the DB
		allusers = hibernateUserDAO.getUsers();
		assertEquals(2, allusers.size());
		assertTrue(allusers.contains(jack));
		assertTrue(allusers.contains(ornophre));
	}
}
